function NuderInvoker(tokens) {
	
	var tinv = new TITTInvoker(tokens, "nuder");
	var key = KeyFactory.createKey(tokens);

	this.dynCall = function(methodName, args, callback) {
		tinv.dynCall(methodName, args, callback);
	}
	
	this.advCall = function(methodName, retType, args, callback) {
		this.call(methodName, args, callback);
	}

	this.call = function(methodName, args, callback){
		var nreq = null;	

		if(args.length > 0 && isNuderRequest(args[args.length -1])) {
			var targs = [];
			for(var i = 0; i < args.length-1; i++)
				targs[i] = args[i];
			nreq = args[args.length-1].getObject();
			args = targs;
		}

		var m = new MethodHeadInit(methodName, args, [], new RequestHeadInit(TITTValues.GET, key.asKeyString(), HeadFactory.EMPTY)); 

		if(nreq) {
			nreq.writeToStream(m, function(val) {
				doCallback(new InternalNuderResponse(val), callback);	
			});
		}
		else {
			var ts = IOFactory.createTITTSocket();
			ts.getHeadWriter().writeHead(m);
			ts.getOutputStream().flush(function() {
				ts.getHeadReader().readHead();
				doCallback(new InternalNuderResponse(ts.getInputStream().readFully()), callback);
			});

		}
	}
	
	function doCallback(obj, callback) {
//		out("in cb")
		callback(new TypedObject(new TypeFromObject(obj), obj));
	}
	
	function isNuderRequest(t) {
		var s = "function NuderRequest("
		
		var m = "" + t.getObject().constructor;
		return m.substring(0, s.length) == s;
	}
}